/*
 * main.c
 *
 *  Created on: Aug 28, 2012
 *      Author: Vasile Guta Ciucur
 *
 *  Description: The application scrolls the following text on 7 seg. 4 digits,
 *               from the right to left:
 *               "HELLO FANS OF PASCAL And C LANGUAGES"
 *
 *******************************************************************************
 *  BSD License.
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  - Neither the name of Vasile Guta Ciucur nor the names of
 *    its contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

//Enable the following definitions on "atmegaclib.h" header:

//#define ENABLE_MILLIS // enable millis()
//#define ENABLE_7SEG   // starting from one digit, up to eight digits.

//Then, define the pins and the number of digits in the user zone, on the
// same header.

#ifndef F_CPU
	#define F_CPU 16000000U //required by Atmel Studio 6
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <atmegaclib.h>

uint16_t scroll_interval = 300, // millisec. scroll speed - it can be faster but hard to read
		led_interval = 150; // blink led at 150 milliseconds interval
uint32_t scrollMillis = 0, ledMillis = 0;
// the following array stores the codes for characters defined in the library
uint8_t i_text, text_string[] = {
		36,36,36,            //three spaces
		19,14,21,21,0,36,    // HELLO
		15,10,29,16,36,      // FANS
		0,15,36,             // OF
		23,10,16,12,10,21,36,// PASCAL
		10,30,13,36,         // And
		12,36,               // C
		21,10,29,35,24,10,35,14,16,36, //LANGUAGES
		36,36,36 // more spaces.
};

void textbuffer_to_segbuffer(uint8_t idx){
	SEG_DIGITS_BUFFER[3] = text_string[idx];
	SEG_DIGITS_BUFFER[2] = text_string[idx + 1];
	SEG_DIGITS_BUFFER[1] = text_string[idx + 2];
	SEG_DIGITS_BUFFER[0] = text_string[idx + 3];
}

void seg_display_from_buffer(void){
	seg_select_digit(SELECT_DIGIT_FOUR, 0);
	seg_nibble(seg_digit_from_array(36)); // first, turn off digit
	seg_nibble(seg_digit_from_array(SEG_DIGITS_BUFFER[3])); //then, take the index char from buffer
	_delay_us(SEG_DELAY); //by default, this is a 1500 usec delay to avoid ghost effect
	seg_select_digit(SELECT_DIGIT_THREE, 0);
	seg_nibble(seg_digit_from_array(36)); // turn off digit
	seg_nibble(seg_digit_from_array(SEG_DIGITS_BUFFER[2]));
	_delay_us(SEG_DELAY);
	seg_select_digit(SELECT_DIGIT_TWO, 0);
	seg_nibble(seg_digit_from_array(36)); // turn off digit
	seg_nibble(seg_digit_from_array(SEG_DIGITS_BUFFER[1]));
	_delay_us(SEG_DELAY);
	seg_select_digit(SELECT_DIGIT_ONE, 0);
	seg_nibble(seg_digit_from_array(36)); // turn off digit
	seg_nibble(seg_digit_from_array(SEG_DIGITS_BUFFER[0]));
	_delay_us(SEG_DELAY);
}


void main(void) __attribute__((noreturn)); //this allows me to have a void main() function
void main (void)
{
	sbi(DDRC, 0);//digital output - led.

	// initializes the buffer, and set the (involved) pins direction
	seg_init();
	millis_init(); // timer0 interrupt
	sei(); // activate interrupts
	i_text = 0; // the current index of text array
	textbuffer_to_segbuffer(i_text);
	while(1){
		//
		uint32_t currentMillis = millis();
		seg_display_from_buffer();
		//
		if ((currentMillis - ledMillis) > led_interval ){
			tbi(PORTC, PC0);
			ledMillis=currentMillis;
		}
		if ((currentMillis - scrollMillis) > scroll_interval ){
			i_text += 1;
			if (i_text == 40) i_text = 0;
			textbuffer_to_segbuffer(i_text);
			scrollMillis=currentMillis;
		}
	}
}

